package com.wzq.factory;


import com.wzq.annotation.WzqAutowired;
import com.wzq.annotation.WzqService;

import com.wzq.annotation.WzqTransactional;
import org.apache.commons.lang.StringUtils;
import org.reflections.Reflections;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 工厂类，生产对象（使用反射技术）
 *
 * @author wzq.Jolin
 * @company none
 * @create 2020-07-01 11:26
 */
public class BeanFactory {
    /**
     * 存储对象容器
     */
    private static Map<String, Object> beanContainer = new HashMap<>();


    static {
        //获取反射对象集合
        Reflections reflections = new Reflections("com.wzq");
        //获取service集合
        Set<Class<?>> serviceTypeSet = reflections.getTypesAnnotatedWith(WzqService.class);

        //将包含WzqService注解的类进行反射实例化，然后放到容器中
        getWzqService(serviceTypeSet);
        //对包含WzqAutowired的对象进行依赖注入
        beanContainer.forEach((key, value) -> {
            Class<?> aClass = value.getClass();
            //获取对象的属性集合
            Field[] declaredFields = aClass.getDeclaredFields();
            //遍历属性，将持有Autowired注解的对象注入进去
            for (Field field : declaredFields) {
                if (field.isAnnotationPresent(WzqAutowired.class)
                        && field.getAnnotation(WzqAutowired.class).required()) {

                    String[] names = field.getType().getName().split("\\.");
                    String name = names[names.length - 1];
                    Method[] methods = aClass.getMethods();

                    for (Method method : methods) {
                        // 该方法就是 setAccountDao(AccountDao accountDao)
                        if (method.getName().equalsIgnoreCase("set" + name)) {
                            try {
                                method.invoke(value, beanContainer.get(name));
                            } catch (IllegalAccessException | InvocationTargetException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                    //判断是否持有WzqTransactional注解，如果有则使用代理对象
                    if (aClass.isAnnotationPresent(WzqTransactional.class)) {
                        //使用代理类
                        isWzqTransactional(aClass, value,key);
                    }
                }
            }
        });


    }

    /**
     * 将含有@WzqService注解的类实例化方式map中
     * @param serviceTypeSet
     */
    private static void getWzqService( Set<Class<?>> serviceTypeSet ) {
        serviceTypeSet.forEach(clazz -> {
            try {
                Object bean = clazz.newInstance();
                WzqService wzqService = clazz.getAnnotation(WzqService.class);

                if (StringUtils.isNotBlank(wzqService.value())) {
                    beanContainer.put(wzqService.value(), bean);
                } else {
                    //getName获取的是全限定类名，分割去掉前面包名部分
                    String[] names = clazz.getName().split("\\.");
                    beanContainer.put(names[names.length - 1], bean);
                }
            } catch (InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
            }
        });
    }

    private static void isWzqTransactional(Class<?> aClass, Object value,String key) {
        //获取代理工厂
        ProxyFactory proxyFactory = (ProxyFactory) BeanFactory.getBean("proxyFactory");
        //获取类c实现的所有接口
        Class[] face = aClass.getInterfaces();
        //判断对象是否实现接口
        if (face != null && face.length > 0) {
            //实现使用JDK
            value = proxyFactory.getJdkProxy(value);
        } else {
            //没实现使用CGLIB
            value = proxyFactory.getCglibProxy(value);
        }
        // 把处理之后的object重新放到map中
        beanContainer.put(key,value);
    }

    /**
     * @解决@2 对外提供获取实例对象的接口（根据id获取）
     */
    public static Object getBean(String id) {
        return beanContainer.get(id);
    }


}
